{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.datasets import fetch_olivetti_faces\n",
    "\n",
    "data_home='datasets/'\n",
    "\n",
    "faces=fetch_olivetti_faces(data_home=data_home)  #先看目录下是否已经存在数据，不存在的话会去下载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X=faces.data\n",
    "y=faces.target\n",
    "\n",
    "targets=np.unique(y)  #查看分类的数量\n",
    "target_names=np.array(['c_%d'%t for t in targets])  #给每个类别一个名字，用于显示图片\n",
    "print(target_names)\n",
    "print(targets)\n",
    "n_samples,h,w=faces.images.shape  #获得样本数，以及每张图片的大小\n",
    "print(faces.images.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_gallery(images, titles, h, w, n_row=2, n_col=5):\n",
    "    \"\"\"显示图片阵列\"\"\"\n",
    "    plt.figure(figsize=(2 * n_col, 2.2 * n_row), dpi=144)\n",
    "    for i in range(n_row * n_col):\n",
    "        plt.subplot(n_row, n_col, i + 1)\n",
    "        plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)\n",
    "        plt.title(titles[i])\n",
    "        plt.axis('off')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#对类标号为0-11的12个类，各随机选择一张图片并将其画出来\n",
    "n_row = 2\n",
    "n_col = 6\n",
    "\n",
    "sample_images = None\n",
    "sample_titles = []\n",
    "for i in range(len(targets)-1):\n",
    "    people_images = X[y==i]\n",
    "    people_sample_index = np.random.randint(0, people_images.shape[0], 1)  #随机选择某个类别的一张图片的index\n",
    "    people_sample_image = people_images[people_sample_index, :]\n",
    "    if sample_images is not None:\n",
    "        sample_images = np.concatenate((sample_images, people_sample_image), axis=0)  #数组的拼接，相当于append\n",
    "    else:\n",
    "        sample_images = people_sample_image\n",
    "    sample_titles.append(target_names[i])\n",
    "\n",
    "plot_gallery(sample_images, sample_titles, h, w, n_row, n_col)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.svm import SVC\n",
    "\n",
    "X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=4)\n",
    "\n",
    "clf=SVC(class_weight='balanced')  #class_weight参数，让模型能根据训练样本的数量来均衡地调整C参数\n",
    "\n",
    "clf.fit(X_train,y_train)\n",
    "\n",
    "y_pred=clf.predict(X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.metrics import confusion_matrix,classification_report\n",
    "\n",
    "cm=confusion_matrix(y_test,y_pred)  #混淆矩阵\n",
    "np.set_printoptions(threshold=np.nan)  #设置numpy，确保完整的输出混淆矩阵的内容\n",
    "print(cm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(classification_report(y_test,y_pred))  #查看分类报告"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#数据还原率\n",
    "\n",
    "from sklearn.decomposition import PCA\n",
    "\n",
    "print(\"Exploring explained variance ratio for dataset ...\")\n",
    "candidate_components = range(10, 300, 30)  #n_components的取值范围\n",
    "explained_ratios = []  # 数据还原率\n",
    "\n",
    "'''\n",
    "有两个PCA类的成员值得关注。第一个是explained_variance_，它代表降维后的各主成分的方差值。方差值越大，则说明越是重要的主成分。\n",
    "\n",
    "第二个是explained_variance_ratio_，它代表降维后的各主成分的方差值占总方差值的比例，这个比例越大，则越是重要的主成分。\n",
    "'''\n",
    "'''\n",
    "对n_components取值范围中的每个值，建模，计算其数据还原率\n",
    "'''\n",
    "\n",
    "for c in candidate_components:\n",
    "    pca = PCA(n_components=c)\n",
    "    X_pca = pca.fit_transform(X)\n",
    "    explained_ratios.append(np.sum(pca.explained_variance_ratio_))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#以n_components为x轴，数据还原率为y轴，画图\n",
    "\n",
    "plt.figure(figsize=(10, 6), dpi=144)\n",
    "plt.grid()\n",
    "plt.plot(candidate_components, explained_ratios)\n",
    "plt.xlabel('Number of PCA Components')\n",
    "plt.ylabel('Explained Variance Ratio')\n",
    "plt.title('Explained variance ratio for PCA')\n",
    "plt.yticks(np.arange(0.5, 1.05, .05))\n",
    "plt.xticks(np.arange(0, 300, 20));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#寻找SVC模型的最佳参数\n",
    "\n",
    "from sklearn.model_selection import GridSearchCV\n",
    "\n",
    "print(\"Searching the best parameters for SVC ...\")\n",
    "param_grid = {'C': [1, 5, 10, 50, 100],\n",
    "              'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01]}\n",
    "clf = GridSearchCV(SVC(kernel='rbf', class_weight='balanced'), param_grid, verbose=1)#, n_jobs=4)\n",
    "clf = clf.fit(X_train_pca, y_train)\n",
    "print(\"Best parameters found by grid search:\")\n",
    "print(clf.best_params_)\n",
    "print(clf.best_estimator_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#我们希望数据还原率高于95%，则可以选择n_components为140\n",
    "n_components=140\n",
    "\n",
    "#建立PCA模型，并用它对训练样本集和测试样本集进行降维\n",
    "pca=PCA(n_components=n_components,svd_solver='auto',whiten=True).fit(X_train)\n",
    "\n",
    "X_train_pca=pca.transform(X_train)\n",
    "X_test_pca=pca.transform(X_test)\n",
    "\n",
    "#创建SVC模型，用于对降维后的数据进行分类\n",
    "\n",
    "#其中，SVC模型的参数是通过GridSearchCV计算得出\n",
    "\n",
    "clf=SVC(kernel='rbf',C=10.0,gamma=0.001)\n",
    "clf.fit(X_train_pca,y_train)\n",
    "y_pred=clf.predict(X_test_pca)\n",
    "cm=confusion_matrix(y_test,y_pred)  #混淆矩阵\n",
    "cm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(classification_report(y_test,y_pred)) #分类报告"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
